###################################################
# Samba4 parser generator for swig wrappers
# Copyright tpot@samba.org 2004,2005
# Copyright jelmer@samba.org 2006
# released under the GNU GPL

package Parse::Pidl::Samba4::SWIG;

use vars qw($VERSION);
use Parse::Pidl::Samba4 qw(DeclLong);
use Parse::Pidl::Typelist qw(mapTypeName);
use Parse::Pidl::Util qw(has_property);
$VERSION = '0.01';

use strict;

my $ret = "";
my $tabs = "";

sub pidl($)
{
	my $p = shift;
	$ret .= $tabs. $p . "\n";
}

sub indent() { $tabs.="\t"; }
sub deindent() { $tabs = substr($tabs,0,-1); }

sub IgnoreInterface($$)
{
	my ($basename,$if) = @_;

	foreach (@{$if->{TYPES}}) {
		next unless (has_property($_, "public"));
		pidl "\%types($_->{NAME});";
	}
}

sub ParseInterface($$)
{
	my ($basename,$if) = @_;

	pidl "\%inline {";
	pidl "struct $if->{NAME} { struct dcerpc_pipe *pipe; };";
	pidl "}";
	pidl "";
	pidl "\%extend $if->{NAME} {";
	indent();
	pidl "$if->{NAME} (const char *binding, struct cli_credentials *cred = NULL, TALLOC_CTX *mem_ctx = NULL, struct event_context *event = NULL)";
	pidl "{";
	indent;
	pidl "struct $if->{NAME} *ret = talloc(mem_ctx, struct $if->{NAME});";
	pidl "NTSTATUS status;";
	pidl "";
	pidl "status = dcerpc_pipe_connect(mem_ctx, &ret->pipe, binding, &ndr_table_$if->{NAME}, cred, event);";
	pidl "if (NT_STATUS_IS_ERR(status)) {";
	pidl "\tntstatus_exception(status);";
	pidl "\treturn NULL;";
	pidl "}";
	pidl "";
	pidl "return ret;";
	deindent;
	pidl "}";
	pidl "";
	pidl "~$if->{NAME}() {";
	pidl "\ttalloc_free(self);";
	pidl "}";
	pidl "";

	foreach my $fn (@{$if->{FUNCTIONS}}) {
		pidl "/* $fn->{NAME} */";
		my $args = "";
		foreach (@{$fn->{ELEMENTS}}) {
			$args .= DeclLong($_) . ", ";
		}
		my $name = $fn->{NAME};
		$name =~ s/^$if->{NAME}_//g;
		$name =~ s/^$basename\_//g;
		$args .= "TALLOC_CTX *mem_ctx = NULL";
		pidl mapTypeName($fn->{RETURN_TYPE}) . " $name($args)";
		pidl "{";
		indent;
		pidl "struct $fn->{NAME} r;";
		pidl "NTSTATUS status;";
		pidl "";
		pidl "/* Fill r structure */";

		foreach (@{$fn->{ELEMENTS}}) {
			if (grep(/in/, @{$_->{DIRECTION}})) {
				pidl "r.in.$_->{NAME} = $_->{NAME};";
			} 
		}

		pidl "";
		pidl "status = dcerpc_$fn->{NAME}(self->pipe, mem_ctx, &r);";
		pidl "if (NT_STATUS_IS_ERR(status)) {";
		pidl "\tntstatus_exception(status);";
		if (defined($fn->{RETURN_TYPE})) {
			pidl "\treturn r.out.result;";
		} else {
			pidl "\treturn;";
		}
		pidl "}";
		pidl "";
		pidl "/* Set out arguments */";
		foreach (@{$fn->{ELEMENTS}}) {
			next unless (grep(/out/, @{$_->{DIRECTION}}));

			pidl ("/* FIXME: $_->{NAME} [out] argument is not a pointer */") if ($_->{LEVELS}[0]->{TYPE} ne "POINTER");

			pidl "*$_->{NAME} = *r.out.$_->{NAME};";
		}

		if (defined($fn->{RETURN_TYPE})) {
			pidl "return r.out.result;";
		}
		deindent;
		pidl "}";
		pidl "";
	}

	deindent();
	pidl "};";
	pidl "";

	foreach (@{$if->{TYPES}}) {
		pidl "/* $_->{NAME} */";
	}
	
	pidl "";
}

sub Parse($$$$)
{
    my($ndr,$basename,$header,$gen_header) = @_;

	$ret = "";

	pidl "/* This file is autogenerated by pidl. DO NOT EDIT */";

	pidl "\%module $basename";
	
	pidl "";

	pidl "\%{";
	pidl "#include \"includes.h\"";
	pidl "#include \"auth/credentials/credentials.h\"";
	pidl "#include \"$header\"";
	pidl "#include \"$gen_header\"";
	pidl "%}";
	pidl "\%import \"samba.i\"";
	pidl "";
	pidl "\%inline {";
	pidl "void ntstatus_exception(NTSTATUS status)"; 
	pidl "{";
	pidl "\t/* FIXME */";
	pidl "}";
	pidl "}";
	pidl "";
	foreach (@$ndr) {
		IgnoreInterface($basename, $_) if ($_->{TYPE} eq "INTERFACE");
	}
	pidl "";

	pidl "";

	foreach (@$ndr) {
		ParseInterface($basename, $_) if ($_->{TYPE} eq "INTERFACE");
	}
	#FIXME: Foreach ref pointer, set NONNULL
	#FIXME: Foreach unique/full pointer, set MAYBENULL
	#FIXME: Foreach [out] parameter, set OUTPARAM
	return $ret;
}

1;
